﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SCEM.DTO;
using SCEM.DataLayer;
using SCEM.External;

namespace SCEM.Manutencao
{
    /// <summary>
    /// Gerenciador do módulo de manutenção.
    /// </summary>
    public class GerenciadorManutencao
    {
        /// <summary>
        /// Busca e retorna a quantidade de equipamentos disponíveis para determinado tipo de fisioterapia em um dia dado.
        /// </summary>
        /// <param name="tipoFisioterapiaId">A identificação do tipo de fisioterapia para o qual se deseja saber a quantidade de equipamentos disponíveis.</param>
        /// <param name="diaConsulta">Um DateTime contendo o dia que se deseja consultar.</param>
        /// <returns>A quantidade garantida de equipamentos disponíveis para determinado tipo de fisioterapia no dia selecionado.</returns>
        public int VerificarQuantidadeEquipamentosDisponiveis(string tipoFisioterapiaId, DateTime diaConsulta)
        {
            Guid guidTipoFisioterapia;
            if (!Guid.TryParse(tipoFisioterapiaId, out guidTipoFisioterapia)) return 0;

            using (var context = new SCEMContainer())
            {
                int equipamentosDisponiveis = 0;
                IQueryable<Equipamento> query = context.Equipamentos.Where(e => e.TipoFisioterapiaId == guidTipoFisioterapia);
                foreach (Equipamento equipamento in query.ToList())
                {
                    if (equipamento.InformacoesManutencao.ProximaManutencaoPreventivaAgendada == null)
                        equipamentosDisponiveis++;
                    else if (equipamento.InformacoesManutencao.ProximaManutencaoPreventivaAgendada.Value.Date != diaConsulta.Date)
                        equipamentosDisponiveis++;
                }

                return equipamentosDisponiveis;
            }
        }

        /// <summary>
        /// Busca e retorna uma lista contendo todos os equipamentos que devem ter sua manutenção preventiva realizada em menos de 30 dias, sendo 
        /// que essa manutenção preventiva ainda não foi agendada.
        /// </summary>
        /// <returns>Uma lista contendo todos os equipamentos que satisfaçam essa condição.</returns>
        public List<EquipamentoDTO> ListarEquipamentosAlertaManutencao()
        {
            IEquipamentoDAO dao = new EquipamentoDAO();
            return dao.ListarEquipamentosAlertaManutencao();
        }

        /// <summary>
        /// Busca e retorna uma lista contendo todos os equipamentos que possuem uma manutenção preventiva agendada.
        /// </summary>
        /// <returns>Uma lista contendo todos os equipamentos que possuam uma manutenção preventina agendada.</returns>
        public List<EquipamentoDTO> ListarEquipamentosManutencaoPreventinaAgendada()
        {
            IEquipamentoDAO dao = new EquipamentoDAO();
            return dao.ListarEquipamentosManutencaoPreventinaAgendada();
        }

        /// <summary>
        /// Agenda a manutenção preventiva de um dado equipamento. Caso esse equipamento já possua uma manutenção preventiva agendada, é
        /// considerado que o usuário deseja realizar um reagendamento.
        /// </summary>
        /// <param name="equipamentoId">O identificação do equipamento para o qual se deseja agendar ou reagendar uma manutenção preventiva.</param>
        /// <param name="dataManutencao">A data da manutenção preventiva.</param>
        /// <returns><code>true</code> em caso de sucesso, <code>false</code> caso contrário.</returns>
        public bool AgendarManutencaoPreventiva(string equipamentoId, DateTime dataManutencao)
        {
            IEquipamentoDAO dao = new EquipamentoDAO();
            EquipamentoDTO dto = (EquipamentoDTO)dao.Get(equipamentoId);
            if (dto == null) 
                return false; // Equipamento não encontrado

            InformacoesManutencao informacoesOriginais = dao.GetInformacoesManutencao(equipamentoId);
            if (informacoesOriginais == null)
                return false; // Erro ao buscar as informações de manutenção

            InformacoesManutencao informacoesAtualizadas = new InformacoesManutencao();
            informacoesAtualizadas.DataUltimaManutencaoPreventiva = informacoesOriginais.DataUltimaManutencaoPreventiva;
            informacoesAtualizadas.PeriodoManutencaoPreventivaDias = informacoesOriginais.PeriodoManutencaoPreventivaDias;
            informacoesAtualizadas.ProximaManutencaoPreventivaAgendada = dataManutencao;
            if (dao.UpdateInformacoesManutencao(equipamentoId, informacoesAtualizadas))
            {
                if (dto.TipoFisioterapiaId != null) // O equipamento é usado em uma fisioterapia, disparar alerta para o agendamento
                    ExternalServiceRequestDispatcher.Instance.DispararAlteracaoQuantidadeEquipamentosAgendamento
                        (dto.TipoFisioterapiaId, dataManutencao, VerificarQuantidadeEquipamentosDisponiveis(dto.TipoFisioterapiaId, dataManutencao));
                return true;
            }
            else
                return false; // Erro ao atualizar as informações do equipamento
        }

        /// <summary>
        /// Arquiva a manutenção preventiva associada a um determinado equipamento.
        /// </summary>
        /// <param name="equipamentoId">A identificação do equipamento cuja manutenção preventiva deseja-se arquivar.</param>
        /// <param name="descricao">Uma descrição para essa entrada no histórico.</param>
        /// <returns><code>true</code> em caso de sucesso, <code>false</code> caso esse equipamento não tenha nenhuma manutenção preventiva para ser arquivada.</returns>
        public bool ArquivarManutencaoPreventiva(string equipamentoId, string descricao)
        {
            IEquipamentoDAO dao = new EquipamentoDAO();

            InformacoesManutencao informacoesOriginais = dao.GetInformacoesManutencao(equipamentoId);
            if (informacoesOriginais == null)
                return false; // Erro ao buscar as informações de manutenção

            if (informacoesOriginais.ProximaManutencaoPreventivaAgendada == null)
                return false; // Não havia uma manutenção preventiva agendada para esse equipamento

            InformacoesManutencao informacoesAtualizadas = new InformacoesManutencao();
            informacoesAtualizadas.DataUltimaManutencaoPreventiva = informacoesOriginais.ProximaManutencaoPreventivaAgendada.Value;
            informacoesAtualizadas.ProximaManutencaoPreventivaAgendada = null;
            informacoesAtualizadas.PeriodoManutencaoPreventivaDias = informacoesOriginais.PeriodoManutencaoPreventivaDias;

            if (dao.UpdateInformacoesManutencao(equipamentoId, informacoesAtualizadas))
            {
                ItemHistoricoManutencaoDAO historicoDAO = new ItemHistoricoManutencaoDAO();
                ItemHistoricoManutencaoDTO historicoDTO = new ItemHistoricoManutencaoDTO();

                historicoDTO.EquipamentoId = equipamentoId;
                historicoDTO.TipoManutencao = TipoManutencao.PREVENTIVA;
                historicoDTO.DataManutencao = informacoesAtualizadas.DataUltimaManutencaoPreventiva;
                historicoDTO.Descricao = descricao;

                historicoDAO.Save(historicoDTO);
                return true;
            }
            else
            {
                return false;
            }

        }

    }
}
